package util;

import org.springframework.mock.jndi.SimpleNamingContext;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;
import javax.naming.spi.InitialContextFactoryBuilder;
import javax.naming.spi.NamingManager;
import java.util.Hashtable;

/**
 * @author janm
 */
public abstract class TestUtils {

    public static class NamingContextBuilder implements InitialContextFactoryBuilder {

        /** An instance of this class bound to JNDI */
        private static NamingContextBuilder activated;


        /**
         * Checks if a SimpleNamingContextBuilder is active.
         * @return the current SimpleNamingContextBuilder instance,
         * or <code>null</code> if none
         */
        public static NamingContextBuilder getCurrentContextBuilder() {
            return activated;
        }

        /**
         * If no SimpleNamingContextBuilder is already configuring JNDI,
         * createOrUpdate and activate one. Otherwise take the existing activate
         * SimpleNamingContextBuilder, clear it and return it.
         * <p>This is mainly intended for test suites that want to
         * reinitialize JNDI bindings from scratch repeatedly.
         * @return an empty SimpleNamingContextBuilder that can be used
         * to control JNDI bindings
         * @throws javax.naming.NamingException .
         */
        public static NamingContextBuilder emptyActivatedContextBuilder() throws NamingException {
            if (activated != null) {
                // Clear already activated context builder.
                activated.clear();
            }
            else {
                // Create and activate new context builder.
                NamingContextBuilder builder = new NamingContextBuilder();
                // The activate() call will cause an assigment to the activated variable.
                builder.activate();
            }
            return activated;
        }


        @SuppressWarnings({"CollectionDeclaredAsConcreteClass"})
		private final Hashtable<String, Object> boundObjects = new Hashtable<String, Object>();


        /**
         * Register the context builder by registering it with the JNDI NamingManager.
         * Note that once this has been done, <code>new InitialContext()</code> will always
         * return a context from this factory. Use the <code>emptyActivatedContextBuilder()</code>
         * static method to get an empty context (for example, in test methods).
         * @throws IllegalStateException if there's already a naming context builder
         * registered with the JNDI NamingManager
         * @throws javax.naming.NamingException .
         */
        public void activate() throws IllegalStateException, NamingException {
            if (!NamingManager.hasInitialContextFactoryBuilder()) NamingManager.setInitialContextFactoryBuilder(this);
            activated = this;
        }

        /**
         * Clear all bindings in this context builder.
         */
        public void clear() {
            this.boundObjects.clear();
        }

        /**
         * Bind the given object under the given name, for all naming contexts
         * that this context builder will generate.
         * @param name the JNDI name of the object (e.g. "java:comp/env/jdbc/myds")
         * @param obj the object to bind (e.g. a DataSource implementation)
         */
        public void bind(String name, Object obj) {
            this.boundObjects.put(name, obj);
        }

        /**
         * Simple InitialContextFactoryBuilder implementation,
         * creating a new SimpleNamingContext instance.
         * @see org.springframework.mock.jndi.SimpleNamingContext
         */
        public InitialContextFactory createInitialContextFactory(Hashtable environment) {
            return new InitialContextFactory() {
                public Context getInitialContext(Hashtable environment) {
                    return new SimpleNamingContext("", boundObjects, environment);
                }
            };
        }

    }

}
